package com.wandian.texas;

import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import com.wandian.centerserver.CenterSessionMgr;
import com.wandian.executor.TimerCommand;
import com.wandian.texas.db.CommonDaoManager;
import com.wandian.texas.db.DBMgr;
import com.wandian.texas.protocol.Protocol;
import com.wandian.util.Log;
import com.wandian.xml.RoomConfigItem;

/**
 * @author long
 * @date 2012-12-7 下午5:53:10
 * @qq 108232706
 * @description CenterRequestor
 */
public class CenterRequestor extends Requestor {
	private final Map<Short, String> cmdSocket = new HashMap<Short, String>();
	public boolean isValid = false;
	private final TimerCommand timer;
	public final Object syn = new Object();

	public CenterRequestor(String _name, String _ip, int _port) {
		super(_name, _ip, _port);
		// 不停的重复连，直到连接上了，取消该任务
		timer = new TimerCommand("ReConnect", Protocol.CHATROOM_DELAY_MESSAGE, 0, this.ConnectTimeOut, -1, TimeUnit.SECONDS);
		timer.put("Type", GameData.CMD_RECONNECT);
		this.isReConnect = true;
		this.ConnectTimeOut = 20;
		cmdSocket.put(CenterSessionMgr.CMD_CENTER_LOGIN, "CenterSessionMgr.CMD_CENTER_LOGIN");
		cmdSocket.put(CenterSessionMgr.CMD_SENDSYSTEMTOTALWIN, "CenterSessionMgr.CMD_SENDSYSTEMTOTALWIN");
		cmdSocket.put(CenterSessionMgr.CMD_USINGDCORNUCOPIA, "CenterSessionMgr.CMD_USINGDCORNUCOPIA");
		cmdSocket.put(CenterSessionMgr.CMD_SENDCORNUCOPIA, "CenterSessionMgr.CMD_SENDCORNUCOPIA");
		cmdSocket.put(CenterSessionMgr.CMD_BROADCASTSENDCORNUCOPIA, "CenterSessionMgr.CMD_BROADCASTSENDCORNUCOPIA");
		cmdSocket.put(CenterSessionMgr.CMD_BROADCASTTIMEOUTCORNUCOPIA, "CenterSessionMgr.CMD_BROADCASTTIMEOUTCORNUCOPIA");
		cmdSocket.put(CenterSessionMgr.CMD_BROADCASTUPDATECORNUCOPIAPER30S, "CenterSessionMgr.CMD_BROADCASTUPDATECORNUCOPIAPER30S");
	}

	@Override
	public void OnCommand(Requestor requestor) {
		Log.debug("GameServer OnCommand " + cmdSocket.get(requestor.getRecCmd()));
		switch (requestor.getRecCmd()) {
		case CenterSessionMgr.CMD_BROADCASTUPDATECORNUCOPIAPER30S: {
//			requestor.StatusList.append("CMD_BROADCASTUPDATECORNUCOPIAPER30S|");
			broadcastUpdateCornucopiaPer30s();
			break;
		}
		case CenterSessionMgr.CMD_SENDSYSTEMTOTALWIN: {
//			requestor.StatusList.append("CMD_SENDSYSTEMTOTALWIN|");
			responseSendSystemTotalWin();
			break;
		}
		case CenterSessionMgr.CMD_CENTER_LOGIN:
//			requestor.StatusList.append("CMD_CENTER_LOGIN|");
			responseLogin();
			break;
		case CenterSessionMgr.CMD_ALLOWCORNUCOPIA:
//			requestor.StatusList.append("CMD_ALLOWCORNUCOPIA|");
			responseAllowCornucopia();
			break;
		case CenterSessionMgr.CMD_USINGDCORNUCOPIA:
//			requestor.StatusList.append("CMD_USINGDCORNUCOPIA|");
			// responseLogin();
			break;
		case CenterSessionMgr.CMD_SENDCORNUCOPIA:
//			requestor.StatusList.append("CMD_SENDCORNUCOPIA|");
			responseSendCornucopia();
			break;
		case CenterSessionMgr.CMD_BROADCASTSENDCORNUCOPIA:
//			requestor.StatusList.append("CMD_BROADCASTSENDCORNUCOPIA|");
			broadcastSendCornucopia();
			break;
		case CenterSessionMgr.CMD_BROADCASTTIMEOUTCORNUCOPIA:
//			requestor.StatusList.append("CMD_BROADCASTTIMEOUTCORNUCOPIA|");
			broadcastTimeOutCornucopia();
			break;
		default:
//			requestor.readEnd();
			break;
		}
		requestor.readEnd();
	}

	public float toCornucopia;
	public float offsetCornucopia;
	public int updateCornucopiaSecond;

	private void broadcastUpdateCornucopiaPer30s() {
		toCornucopia = this.readFloat();
		offsetCornucopia = this.readFloat();
		updateCornucopiaSecond = this.readInt();
		this.readEnd();
//		synchronized (this.dataPacket) {
		BaseCommandObject cmd = this.getFreeCommand();
		cmd.setCmd(Protocol.CMD_UPDATE_CORNUCOPIA);
		cmd.writeBegin();
		cmd.writeFloat(toCornucopia);
		cmd.writeFloat(offsetCornucopia);
		cmd.writeInt(updateCornucopiaSecond);
		cmd.writeEnd();
		UserMgr.I().broadCastToAllOnlines(cmd);
		freeUsedCommand(cmd);
//		}
	}

	@Override
	void onCloseSessionKey(SelectionKey key) {
		this.isValid = false;
		Log.info("与中心服务器断开");
		if (this.isReConnect) {
			Log.info("与中心服务器断开,重新连接");
			if (ThreadPool.getInstance().isThreadPoolStated()) {
				ThreadPool.getInstance().Push(timer);
			} else {
				Log.error("与中心服务器断开,重新连接,但是线程池没有启动！");
			}

		}
	}

	public void requestLogin() {
//		synchronized (this.dataPacket) {
		BaseCommandObject cmd = this.getFreeCommand();
		cmd.setCmd(CenterSessionMgr.CMD_CENTER_LOGIN);
		cmd.writeBegin();
		cmd.writeInt(GameData.SERVER.ServerId);
		cmd.writeEnd();
		this.SendData(cmd);
//		}
	}

	/**
	 * 如果是发送之前累计的数，只需要全部是0
	 * 
	 * @param roomId
	 * @param gameId
	 * @param systemWin
	 */
	public void requestSendSystemTotalWin(int roomId, int gameId, float systemWin) {
		try {
			// GameData.SERVER.SystemTotalWin += systemWin;
			GameData.InCreaceSystemTotalWin(systemWin);
			if (GameData.getSystemTotalWin() == 0) {
				Log.info("累积盈利为0,,不需要发送");
				return;
			}
			if (!isSendSystemWinSuc) {
				Log.debug("上一次发送的累加还未返回,本次盈利累计到内存");
				return;
			}
			if (!this.connected || !this.isValid) {
				Log.error("中心服务器连接出问题");
				return;
			}
			hasSendSystemWin = GameData.getSystemTotalWin();
			GameData.InCreaceSystemTotalWin(-hasSendSystemWin);
//			synchronized (this.dataPacket) {
			BaseCommandObject cmd = this.getFreeCommand();

			cmd.setCmd(CenterSessionMgr.CMD_CENTER_SERVER);
			cmd.writeBegin();
			cmd.writeByte((byte) 13);
			cmd.writeInt(roomId);
			cmd.writeInt(gameId);
			cmd.writeFloat(systemWin);//当前游戏的盈利
			cmd.writeFloat(hasSendSystemWin);//上次成功发送到本次，系统总盈利
			cmd.writeEnd();
			this.SendData(cmd);
//			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
		}
//		isSendSystemWinSuc = false;// 等待服务端验证
//		Log.info("游戏结束，发送盈利成功,发送数"+hasSendSystemWin);

		// 需要等中心端确认才可以清除缓存
	}

	private boolean isSendSystemWinSuc = true;
	private float hasSendSystemWin;

	/**
	 * 盈利累加应答模式为1-1，只有请求被响应了，才可以继续请求
	 */
	public void responseSendSystemTotalWin() {
		isSendSystemWinSuc = this.readByte() == 0 ? true : false;
		this.readEnd();
//		Log.info(String.format("中心端验证盈利累计%s", isSendSystemWinSuc ? "成功" : "失败"));
		if (isSendSystemWinSuc) {
			// 验证ok，后面可能出现很多次未请求的累计，发送的累计小于此数
			// GameData.SERVER.SystemTotalWin -= hasSendSystemWin;
			GameData.InCreaceSystemTotalWin(-hasSendSystemWin);
			//成功的数据从累计里减少，同时把同步成功的钱加入SendMoney，没有Send的更新
			if (CommonDaoManager.GameRoomDao(0).executeNoQuery("sp_AddSendMoney", DBMgr.TexasPokerDB, GameData.SERVER.ServerId, hasSendSystemWin, GameData.getSystemTotalWin()) == -1) {
				Log.error("更新发送钱失败!");
			}
		}
		isSendSystemWinSuc = true;// 下次请求可以开始了
	}

	/**
	 * 游戏开始，洗到积宝牌请求积宝
	 */
	public void requestAllowCornucopia(int cardType, int roomId, int seatId, int userId, int idx) {
		Log.info("requestAllowCornucopia:cardType" + cardType + " roomId:" + roomId + " seatId:" + seatId + " userId:" + userId + " idx:" + idx);
		if (!this.connected || !this.isValid) {
			Log.error("中心服务器连接出问题");
			return;
		}
		BaseCommandObject cmd = this.getFreeCommand();
		try {
			if (!this.socketChannel.isConnected()) {
				Log.error("中心服务器连接出问题，产生积宝牌，请求允许消息抛弃");
				return;
			}
//			synchronized (this.dataPacket) {
			cmd.setCmd(CenterSessionMgr.CMD_CENTER_SERVER);
			cmd.writeBegin();
			cmd.writeByte((byte) 10);
			cmd.writeInt(roomId);
			cmd.writeInt(seatId);
			cmd.writeInt(userId);
			cmd.writeInt(idx);
			cmd.writeByte((byte) cardType);
			cmd.writeEnd();
			this.SendData(cmd);
//			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
		}
	}

	/**
	 * 游戏结束，通知游戏服务器,积宝指标有没有被使用
	 */
	public void requestSendCornucopia(boolean isShowCardAndWinCornu, String cornucopiaCallBack, int cardType, int roomId, int seatId, int userId, int idx, String nickName, String maxCards) {
		try {
			if (!this.connected || !this.isValid) {
				Log.error("中心服务器连接出问题");
				return;
			}
			// 游戏结束，通知产生积宝，当前房间积宝置为不允许，防止新游戏开始，没有收到服务器确认，还在发积宝牌
			RoomConfigItem room = RoomMgr.getRoom(roomId);
			room.isAllowCornucopia(false);
			room.isCornucopiaSend(true);
			room.isUsingCornucopia(false);
			if (!this.connected || !this.isValid || !this.isValid) {
				Log.error("中心服务器连接出问题，消息抛弃");
				return;
			}
			Log.info("[请求中心发积宝]roomId:" + roomId + " cornucopiaCallBack:" + cornucopiaCallBack + " seatId:" + seatId + " cardType:" + cardType + " userId:" + userId + " idx:" + idx + " nickName:" + nickName + " maxCards:" + maxCards);
//			synchronized (this.dataPacket) {
			BaseCommandObject cmd = this.getFreeCommand();
			cmd.setCmd(CenterSessionMgr.CMD_CENTER_SERVER);
			cmd.writeBegin();
			cmd.writeByte((byte) 12);
			cmd.writeInt(roomId);
			cmd.writeInt(room.gameId());
			cmd.writeInt(seatId);
			cmd.writeInt(userId);
			cmd.writeInt(idx);
			cmd.writeString(nickName);
			cmd.writeByte((byte) cardType);
			cmd.writeString(cornucopiaCallBack);
			cmd.writeByte(isShowCardAndWinCornu ? (byte) 0 : (byte) 1);
			cmd.writeString(maxCards);
			cmd.writeEnd();
			this.SendData(cmd);
//			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
		}
	}

	/**
	 * 游戏使用中心服务器允许的积宝洗牌，通知中心服务器我已使用了，因为10分钟游戏服务端不响应，中心服务器会取消该积宝
	 */
	public void requestUsingdCornucopia(boolean isUsing, String cornucopiaCallBack, int cardType, int roomId, int seatId, int userId, int idx) {
		try {
			if (!this.connected || !this.isValid) {
				Log.error("中心服务器连接出问题，消息抛弃");
				return;
			}
			Log.info("[请求使用积宝]requestUsingdCornucopia:roomId ,seatId,cardType,  userId,  idx" + roomId + " " + seatId + " " + cardType + " " + userId + " " + idx);
//			synchronized (this.dataPacket) {
			BaseCommandObject cmd = this.getFreeCommand();
			cmd.setCmd(CenterSessionMgr.CMD_CENTER_SERVER);
			cmd.writeBegin();
			cmd.writeByte((byte) 11);
			cmd.writeInt(roomId);
			cmd.writeInt(seatId);
			cmd.writeInt(userId);
			cmd.writeByte((byte) cardType);
			cmd.writeString(cornucopiaCallBack);
			cmd.writeByte(isUsing ? (byte) 0 : (byte) 1);
			cmd.writeEnd();
			this.SendData(cmd);
//			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
		}
	}

	public void responseAllowCornucopia() {
		boolean isAllow = this.readByte() == 0 ? true : false;
		int roomid = this.readInt();
		// 下一局开始，通知发积宝
		RoomConfigItem room = RoomMgr.getRoom(roomid);
		// room.isGenerateCornucopia = false;// 防止洗牌再次出积宝,一交换请求段只出一个
		if (isAllow) {
			int seatId = this.readInt();
			int userid = this.readInt();
			int idx = this.readInt();
			byte cardType = this.readByte();
			String cornucopiaCallBack = this.readString();// 回调id
			room.isAllowCornucopia(true);
			room.isCornucopiaSend(false);
			room.isUsingCornucopia(false);
			room.cornucopiaSeatId(seatId);
			room.cornucopiaUserId(userid);
			room.cornucopiaidx(idx);
			room.cornucopiaCardType(cardType);
			room.cornucopiaCallBack(cornucopiaCallBack);
			Log.info("responseAllowCornucopia:cardType" + cardType + " roomId:" + roomid + "  seatId:" + seatId + " userId:" + userid + " idx:" + idx);
		} else {
			room.isAllowCornucopia(false);
		}
		this.readEnd();
//		Log.info(String.format("请求发积宝%s", isAllow ? "成功" : "失败"));
	}

	/**
	 * 中心服务器响应发送确认
	 */
	public void responseSendCornucopia() {
		boolean isSend = this.readByte() == 0 ? true : false;
		String cornucopiaCallBack = this.readString();// 回调id
		byte cardType = this.readByte();
		int roomid = this.readInt();
		int userid = this.readInt();
		int idx = this.readInt();
		this.readEnd();
		Log.info(String.format("确认发积宝%s", isSend ? "成功" : "失败"));
		// 下一局开始，通知发积宝
		RoomConfigItem room = RoomMgr.getRoom(roomid);
		room.isAllowCornucopia(false);
		room.isCornucopiaSend(true);
		room.isUsingCornucopia(false);
		room.cornucopiaCardType(cardType);
		room.cornucopiaUserId(userid);
		room.cornucopiaidx(idx);
	}

	/**
	 * 中心服务器响广播发积宝消息
	 */
	public void broadcastSendCornucopia() {
		int serverid = this.readInt();
		int roomid = this.readInt();
		int userid = this.readInt();
		int idx = this.readInt();
		String nickName = this.readString();
		String cornucopiaCallBack = this.readString();
		byte cardType = this.readByte();
		float money = this.readFloat();
		this.readEnd();
		// 防止当前房间该积宝还在使用
		if (serverid == GameData.SERVER.ServerId) {
			RoomConfigItem room = RoomMgr.getRoom(roomid);
			if (room.isAllowCornucopia() && room.cornucopiaCallBack() == cornucopiaCallBack) {
				room.isAllowCornucopia(false);
				room.isCornucopiaSend(true);
				room.isUsingCornucopia(false);
				room.cornucopiaCardType(cardType);
				room.cornucopiaUserId(userid);
				room.cornucopiaidx(idx);
			}
		}
		Log.info(String.format("中心服务器响广播发积宝消息,userid:%s,%s,cardType:%s,roomid:%s,money:%s", userid, nickName, cardType, roomid, money));
		// 广播消息给全部在线
		BaseCommandObject cmd = this.getFreeCommand();
		cmd.setCmd(Protocol.CMD_REWARD_CORNUCOPIA);
//		DataPacket dataPacket = new DataPacket(Protocol.CMD_REWARD_CORNUCOPIA);
		cmd.writeBegin();
		cmd.writeInt(userid);
		cmd.writeString(nickName);
		cmd.writeInt(cardType);
		cmd.writeFloat(money);
		cmd.writeInt(roomid);
		cmd.writeEnd();
		UserMgr.I().broadCastToAllOnlines(cmd);
		freeUsedCommand(cmd);

	}

	public void broadcastTimeOutCornucopia() {
		int roomid = this.readInt();
		// int seatid = this.readInt();
		// int userid = this.readInt();
		// byte cardType = this.readByte();
		String cornucopiaCallBack = this.readString();// 回调id
		this.readEnd();
		RoomConfigItem room = RoomMgr.getRoom(roomid);
		if (room == null) {
			Log.error("中心服固定时间,未收到游戏端确认，发出回收积宝指标命令，但是该房不存在");
			return;
		}
		room.isAllowCornucopia(false);
		if (room.cornucopiaCallBack() != cornucopiaCallBack) {
//			Log.error("中心服固定时间,未收到游戏端确认，发出回收积宝指标命令，但是积宝回调id不一样");
			return;
		}
		if (room.isUsingCornucopia()) {
			Log.error("中心服固定时间,未收到游戏端确认，发出回收积宝指标命令，但是积宝已经在使用了，难道中心服不取消那个回收定时器？");
			return;
		}
		if (room.cornucopiaCallBack() != cornucopiaCallBack) {
			Log.error("中心服固定时间,未收到游戏端确认，发出回收积宝指标命令，但是积宝回调id不一致");
			return;
		}
		Log.info("中心服固定时间,未收到游戏端确认，发出回收积宝指标命令，游戏端回收成功");
	}

	public void responseLogin() {
		isValid = this.readByte() == 0 ? true : false;
		this.readEnd();
		Log.info(String.format("连接中心服务器%s", isValid ? "成功" : "失败"));
		if (!isValid) {
			requestLogin();
		} else {
			// 系统第一次连接，或者断线连接，都发送累积的盈率
			synchronized (syn) {
				syn.notify();
			}
			requestSendSystemTotalWin(0, 0, 0);
		}
	}

	public void RECONNECT(TimerCommand cmd) {
		try {
			if (GameServer.requestor.connect()) {
				cmd.setCancel(true);
				GameServer.requestor.requestLogin();
			}
		} catch (IOException e) {
			Log.error("Connection refused," + this.ip + ":" + this.port);
		}
	}

}
